#include "NewExpression.h"
#include "ClassDefinition.h"
#include "../Exceptions.h"
#include "../GeneralVisitor.h"
#include "../Constants.h"

NewExpression::NewExpression(string iClassName, vector<TreeNode*> iConstructorParams)
{
    this->fClassName = iClassName;
    this->fConstructorParams = iConstructorParams;
    this->fConstructorDefinition = 0;
}

NewExpression::~NewExpression()
{
    for(vector<TreeNode*>::iterator it = fConstructorParams.begin(); it != fConstructorParams.end(); ++it)
    {
        delete (*it);
    }

    fConstructorParams.clear();
}

void NewExpression::CheckVariables(set<string>& oVariables, string iParentName)
{
    for(vector<TreeNode*>::iterator it = this->fConstructorParams.begin(); it != this->fConstructorParams.end(); ++it)
    {
        (*it)->CheckVariables(oVariables, iParentName);
    }
}

void NewExpression::CheckFunctionCalls(set<FunctionDefinition*>& iAllFunctions, string iParentName)
{
    for(vector<TreeNode*>::iterator it = this->fConstructorParams.begin(); it != this->fConstructorParams.end(); ++it)
    {
        (*it)->CheckFunctionCalls(iAllFunctions, iParentName);
    }
}

void NewExpression::CheckClassConstructions(set<ClassDefinition*>& iAllClasses, string iParentName)
{
    // 1. existuje ta trida vubec?
    ClassDefinition* lClassDef = 0;

    for(set<ClassDefinition*>::iterator it = iAllClasses.begin(); it != iAllClasses.end(); ++it)
    {
        if((*it)->GetClassName() == this->fClassName)
        {
            lClassDef = *it;
            break;
        }
    }

    if(lClassDef == 0)
        throw UndeclaredClassInstantiationException(iParentName, this->fClassName);

    // 2. tridu mam... ted mi zjisti konstruktory
    vector<MethodDefinition*> lAllCOnstructors = lClassDef->GetConstructors();

    // zadny? to je spatne
    if(lAllCOnstructors.size() == 0)
        throw NoConstructorAvailableException(iParentName, this->fClassName);

    // ted mi z nich vyber ten, ktery ma odpovidajici pocet parametru
    for(vector<MethodDefinition*>::iterator it = lAllCOnstructors.begin(); it != lAllCOnstructors.end(); ++it)
    {
        if((*it)->GetParamCount() == this->fConstructorParams.size())
        {
            this->fConstructorDefinition = *it;
            break;
        }
    }

    // zadny s odpovidajicim poctem parametru? to je taky spatne
    if(this->fConstructorDefinition == 0)
        throw NoConstructorAvailableException(iParentName, this->fClassName, this->fConstructorParams.size());

    if(this->fConstructorParams.size() > MAX_METHOD_CALL_PARAMS)
        throw TooMuchCallParamCount(iParentName, fClassName, MAX_METHOD_CALL_PARAMS, fConstructorParams.size());

    // tak a ted to aplikuj i na parametry
    for(vector<TreeNode*>::iterator it = this->fConstructorParams.begin(); it != this->fConstructorParams.end(); ++it)
    {
        (*it)->CheckClassConstructions(iAllClasses, iParentName);
    }
}

void NewExpression::CheckExpressionTypes(map<string, ExpressionType*>& iVarTypes, string iParentName)
{
    for(vector<TreeNode*>::iterator it = this->fConstructorParams.begin(); it != this->fConstructorParams.end(); ++it)
    {
        (*it)->CheckExpressionTypes(iVarTypes, iParentName);
    }
}

ExpressionType* NewExpression::GetType(map<string, ExpressionType*>&, string)
{
    ClassDefinition* lClassDef = this->fConstructorDefinition->GetClassDef();

    return new ExpressionType(UserDefinedObject, false, lClassDef);
}

void NewExpression::Accept(GeneralVisitor* iVisitor)
{
    iVisitor->Visit(this);
}
